package com.wzcl.app.service.common;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wzcl.app.dao.model.AppFile;
import com.wzcl.app.dao.model.AppUser;
import com.wzcl.app.dao.model.Channel;
import com.wzcl.app.dao.model.LiveRoom;
import com.wzcl.app.model.common.BusinessException;
import com.wzcl.app.model.common.CodeMsg;
import com.wzcl.app.model.vo.BaseVo;
import com.wzcl.app.service.AppFileService;
import com.wzcl.app.service.LiveRoomService;
import com.wzcl.app.service.UserService;
import com.wzcl.app.service.common.impl.MyPLChannelServiceImpl;
import com.wzcl.app.service.common.model.body.ChannelAuthSettingBody;
import com.wzcl.app.service.common.model.body.ChannelBasicSettingBody;
import com.wzcl.app.service.common.model.requset.PlChannelAuthGetRequest;
import com.wzcl.app.service.common.model.requset.PlChannelDetailUpdateRequest;
import com.wzcl.app.service.common.model.requset.PlChannelEndRequest;
import com.wzcl.app.service.common.model.result.PLChannelAuthResult;
import com.wzcl.app.utils.MD5Util;
import lombok.extern.log4j.Log4j2;
import net.polyv.live.bean.model.DonateGoods;
import net.polyv.live.bean.request.channel.*;
import net.polyv.live.bean.request.donate.PLChannelDonateGetRequest;
import net.polyv.live.bean.request.donate.PLDonateCashSetRequest;
import net.polyv.live.bean.request.donate.PLDonateGoodsSetRequest;
import net.polyv.live.bean.request.stream.PLChannelStreamCommonRequest;
import net.polyv.live.bean.result.PLCommonResult;
import net.polyv.live.bean.result.channel.*;
import net.polyv.live.bean.result.donate.PLChannelDonateGetResult;
import net.polyv.live.service.*;
import net.polyv.live.service.impl.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Log4j2
@Service
@PropertySource({"classpath:application-config.properties"})
public class PolyvService {
    public static final String WATCH_PREFIX = "https://live.wzclzx.com/watch";
    @Value("${polyv.userId}")
    private String userId;

    @Value("${polyv.appId}")
    private String appId;

    @Value("${polyv.appSecret}")
    private String secret;

    @Value("${polyv.externalUri}")
    private String externalUri;

    @Autowired
    private UserService userService;

    @Autowired
    private AppFileService fileService;

    @Autowired
    private LiveRoomService liveRoomService;

    //频道接口对象
    private PLChannelService plChannelService = new PLChannelServiceImpl();
    //流对象
    private PLChannelStreamService pLChannelStreamService = new PLChannelStreamServiceImpl();
    //频道基本信息对象
    private PLChannelBasicService pLChannelBasicService = new PLChannelBasicServiceImpl();
    //打赏对象
    private PLChannelDonateService plChannelDonateService = new PLChannelDonateServiceImpl();

    //自定义实现接口
    private MyPLChannelService myPLChannelService = new MyPLChannelServiceImpl();

    //创建直播频道
    public Channel createChannel(ChannelBasicSettingBody basicBody, ChannelAuthSettingBody authBody) {
//        // 创建请求参数json对象
//        PLChannelBasicCreateBody createBody = new PLChannelBasicCreateBody();
//        PLChannelBasicSettingCreateBody basicSetting = new PLChannelBasicSettingCreateBody();
//        PLChannelAuthSettingBody authSetting = new PLChannelAuthSettingBody();
//        //设置基础参数
//        BeanUtils.copyProperties(pretreatmentBasicSetting(basicBody), basicSetting);
//        String password = String.valueOf(Math.round(Math.random() * 899999 + 100000));
//        basicSetting.setChannelPasswd(password);
//        createBody.setBasicSetting(basicSetting);
//        //设置观看条件
//        BeanUtils.copyProperties(pretreatmentAuthSetting(authBody), authSetting);
//        createBody.setAuthSettings(authSetting);
//        //构建请求
//        PLChannelBasicCreateRequest request = new PLChannelBasicCreateRequest(appId, secret, createBody);
//        PLChannelBasicCreateResult result = pLChannelBasicService.createChannel(request);
//        if (result.isRequestOk()) {
//            Channel channel = new Channel();
//            channel.setName(result.getName());
//            channel.setChannelId(result.getChannelId());
//            channel.setChannelPasswd(password);
//            channel.setScene(result.getScene());
//            channel.setAvailable(false);
//            return channel;
//        }
//        throw new BusinessException(CodeMsg.POLYV_ERR, result.getMessage());
        PLChannelCreateRequest request = new PLChannelCreateRequest(appId,secret);
        request.setUserId(userId);
        String password = String.valueOf(Math.round(Math.random() * 899999 + 100000));
        request.setChannelPasswd(password);
        request.setName(basicBody.getName());
        request.setScene(basicBody.getScene());
        PLChannelCreateResult result = plChannelService.createChannel(request);
        if(result.isRequestOk()){
            Channel channel = new Channel();
            channel.setName(result.getName());
            channel.setChannelId(result.getChannelId());
            channel.setChannelPasswd(password);
            channel.setScene(basicBody.getScene());
            channel.setAvailable(true);
            return channel;
        }
        throw new BusinessException(CodeMsg.POLYV_ERR, result.getMessage());
    }

    //设置频道最大在线人数
    public void setChannelMaxViewer(Integer ChannelId, Integer maxViewer) {
        // 创建请求对象
        PLChannelMaxViewerSetRequest request = new PLChannelMaxViewerSetRequest(appId, secret);
        // 参数的设置
        request.setUserId(userId);
        request.setMaxViewer(String.valueOf(maxViewer));
        //调 用频道接口对象的创建频道方法获取请求结果对象
        PLChannelCommonResult result = plChannelService.setChannelMaxViewer(ChannelId, request);
        if (!result.isRequestOk()) {
            throw new BusinessException(CodeMsg.POLYV_ERR, result.getMessage());
        }
    }

    //修改频道名称
    public void setChannelName(Integer ChannelId, String name) {
        // 创建请求对象
        PLChannelNameSetRequest request = new PLChannelNameSetRequest(appId, secret);
        // 参数的设置
        request.setName(name);
        //调用
        PLChannelCommonResult result = plChannelService.setChannelName(ChannelId, request);
        if (!result.isRequestOk()) {
            throw new BusinessException(CodeMsg.POLYV_ERR, result.getMessage());
        }
    }

    //设置频道号密码
    public void setChannelPassword(Integer channelId, String password) {
        // 创建请求对象
        PLChannelPasswordSetRequest request = new PLChannelPasswordSetRequest(appId, secret);
        // 参数的设置
        request.setChannelId(channelId);
        request.setPasswd(password);
        //调 用频道接口对象的创建频道方法获取请求结果对象
        PLChannelCommonResult result = plChannelService.setChannelPassword(userId, request);
        if (!result.isRequestOk()) {
            throw new BusinessException(CodeMsg.POLYV_ERR, result.getMessage());
        }
    }

    //获取详细信息
    public PLChannelGetResult getChannel(Integer ChannelId) {
        // 创建请求对象
        PLChannelGetRequest request = new PLChannelGetRequest(appId, secret);
        // 参数的设置
        //调 用频道接口对象的创建频道方法获取请求结果对象
        PLChannelGetResult result = plChannelService.getChannel(ChannelId, request);
        if (result.isRequestOk()) {
            return result;
        }
        throw new BusinessException(CodeMsg.POLYV_ERR, result.getMessage());
    }


    //获取直播状态
    public String getChannelState(String stream) {
        return plChannelService.getChannelLiveStatus(stream);
    }

    //获取直播状态
    public String getChannelState(Integer ChannelId) {
        PLChannelGetRequest request = new PLChannelGetRequest(appId, secret);
        PLChannelGetResult result = plChannelService.getChannel(ChannelId, request);
        if (result.isRequestOk()) {
            return getChannelState(result.getStream());
        }
        throw new BusinessException(CodeMsg.POLYV_ERR, result.getMessage());
    }

    //获取频道暂存的文件信息接口
    public List<RecordFile> getRecordFiles(Integer channelId, Long start, Long end,String sessionId){
        PLChannelRecordFilesGetRequest request = new PLChannelRecordFilesGetRequest(appId,secret);
        request.setUserId(userId);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date date = new Date();
        if(start != null){
            date.setTime(start);
            String startTime = format.format(date);
            request.setStartDate(startTime);
        }
        if(end != null){
            date.setTime(end);
            String endTime = format.format(date);
            request.setEndDate(endTime);
        }
        if(StringUtils.isNotBlank(sessionId)){
            request.setSessionId(sessionId);
        }
        PLChannelRecordFilesGetResult result = plChannelService.getChannelRecordFiles(channelId, request);
        if(result.isRequestOk()){
            return result.getRecordFiles();
        }
        throw new BusinessException(CodeMsg.POLYV_ERR, result.getMessage());
    }

    //获取频道暂存的文件信息接口
    public List<Playback> getPlayBack(Integer channelId,List<String> sessionIdList){
        List<Playback> list = new ArrayList<>();
        PLChannelPlaybackListGetRequest request = new PLChannelPlaybackListGetRequest(appId,secret);
        int i =1;
        boolean flag = false;
        do{
            request.setPage(i++);
            PLChannelPlaybackListGetResult result = plChannelService.getChannelPlaybacks(channelId, request);
            if(result.isRequestOk()){
                if(result.getLimit()>0)list.addAll(result.getPlaybacks().stream().filter(playback -> sessionIdList.contains(playback.getChannelSessionId())).collect(Collectors.toList()));
                flag = result.isLastPage();
                continue;
            }
            throw new BusinessException(CodeMsg.POLYV_ERR, result.getMessage());
        }while (!flag);
        return list;
    }


    public void end(Integer channelId){
        PlChannelEndRequest request = new PlChannelEndRequest(appId,secret,userId);
        PLChannelCommonResult result = myPLChannelService.end(channelId, request);
        if(!result.isRequestOk()){
            throw new BusinessException(CodeMsg.POLYV_ERR, result.getMessage());
        }
    }


    //禁止推流(24小时)
    public void cutoff(Integer channelId) {
        // 创建请求对象
        PLChannelStreamCommonRequest request = new PLChannelStreamCommonRequest(appId, secret);
        // 参数的设置
        request.setUserId(userId);
        //调用
        PLCommonResult result = pLChannelStreamService.cutoff(channelId, request);
        if (!result.isRequestOk()) {
            throw new BusinessException(CodeMsg.POLYV_ERR, result.getMessage());
        }
    }

    //允许推流
    public void resume(Integer channelId) {
        // 创建请求对象
        PLChannelStreamCommonRequest request = new PLChannelStreamCommonRequest(appId, secret);
        // 参数的设置
        request.setUserId(userId);
        //调用
        PLCommonResult result = pLChannelStreamService.resume(channelId, request);
        if (!result.isRequestOk()) {
            throw new BusinessException(CodeMsg.POLYV_ERR, result.getMessage());
        }
    }

    //修改
    public String updateChannel(Integer channelId, ChannelBasicSettingBody basicBody, ChannelAuthSettingBody authBody) {
        //设置基础参数
        PLChannelBasicSettingUpdateBody basicSetting = new PLChannelBasicSettingUpdateBody();
        BeanUtils.copyProperties(pretreatmentBasicSetting(basicBody), basicSetting);
        //设置观看条件
        PLChannelAuthSettingBody authSetting = new PLChannelAuthSettingBody();
        BeanUtils.copyProperties(pretreatmentAuthSetting(authBody), authSetting);
        //包装请求体
        PLChannelBasicUpdateBody body = new PLChannelBasicUpdateBody();
        body.setBasicSetting(basicSetting);
        body.setAuthSettings(Arrays.asList(authSetting));
        //发送请求
        PLChannelBasicUpdateRequest request = new PLChannelBasicUpdateRequest(appId, secret, channelId, body);
        PLChannelCommonResult result = pLChannelBasicService.updateChannel(request);
        if (result.isRequestOk()) {
            return JSON.toJSONString(result);
        }
        throw new BusinessException(CodeMsg.POLYV_ERR, result.getMessage());
    }

    //基本详情相关设置
    public void updateDetail(Integer channelId, String field, String value) {
        PlChannelDetailUpdateRequest request = new PlChannelDetailUpdateRequest(appId, secret);
        //设置参数
        request.setChannelId(channelId);
        request.setField(field);
        request.setValue(value);
        //调用
        PLChannelCommonResult result = myPLChannelService.updateDetail(request);
        if (!result.isRequestOk()) {
            throw new BusinessException(CodeMsg.POLYV_ERR, result.getMessage());
        }
    }


    public String getDonate(Integer channelId){
        PLChannelDonateGetRequest request = new PLChannelDonateGetRequest(appId, secret);
        request.setChannelId(channelId);
        //  获取频道打赏设置请求结果对象
        PLChannelDonateGetResult result = plChannelDonateService.getDonateSetting(request);
        if(result.isRequestOk()) {
            return JSON.toJSONString(request);
        }
        throw new BusinessException(CodeMsg.POLYV_ERR, result.getMessage());
    }

    //频道现金打赏设置接口
    public String setDonateCashes(Integer channelId,Double minCash,List<Double> cashes){
        PLDonateCashSetRequest request = new PLDonateCashSetRequest(appId, secret,channelId,cashes,minCash);
        request.setChannelId(channelId);
        //  获取频道打赏设置请求结果对象
        PLCommonResult  result = plChannelDonateService.setDonateCash(request);
        if(result.isRequestOk()) {
            return JSON.toJSONString(request);
        }
        throw new BusinessException(CodeMsg.POLYV_ERR, result.getMessage());
    }

    //频道道具打赏设置接口
    public String setDonateGoods(Integer channelId,String goodListJson){
        List<DonateGoods> goods = JSONObject.parseArray(goodListJson, DonateGoods.class);
        PLDonateGoodsSetRequest request = new PLDonateGoodsSetRequest(appId, secret,channelId,goods);
        request.setChannelId(channelId);
        //  获取频道打赏设置请求结果对象
        PLCommonResult  result = plChannelDonateService.setDonateGoods(request);
        if(result.isRequestOk()) {
            return JSON.toJSONString(request);
        }
        throw new BusinessException(CodeMsg.POLYV_ERR, result.getMessage());
    }


    public String getWatchUrl(Integer channelId, AppUser user) {
        PlChannelAuthGetRequest request = new PlChannelAuthGetRequest(appId, secret);
        //设置参数
        request.setChannelId(channelId);
        //获得结果
        List<PLChannelAuthResult> auth = myPLChannelService.getAuth(request);
        if (auth == null) {
            return String.format("%s/%d", WATCH_PREFIX, channelId);
        }
        PLChannelAuthResult authResult = null;
        for (PLChannelAuthResult result : auth) {
            if (!"N".equals(result.getEnabled()) && result.getRank() == 1) {
                authResult = result;
                break;
            }
        }
        if (authResult == null) {
            return String.format("%s/%d", WATCH_PREFIX, channelId);
        }
        switch (authResult.getAuthType()) {
            case "external":
                String userid = user.getPhone();
                String ts = String.valueOf(System.currentTimeMillis());
                String sign = MD5Util.toMD5(authResult.getExternalKey() + userid + authResult.getExternalKey() + ts);
                return String.format("%s/%d?userid=%s&ts=%s&sign=%s", WATCH_PREFIX, channelId, userid, ts, sign);
            default:
                return String.format("%s/%d", WATCH_PREFIX, channelId);
        }
    }



    public void notify(HttpServletRequest request, HttpServletResponse response) {
        String userid = request.getParameter("userid");
        String channelId = request.getParameter("channelId");
        String ts = request.getParameter("ts");
        String token = request.getParameter("token");
        boolean check = check(userid, channelId, ts, token);
        try {
            Map<String, Object> returnMap = new HashMap<>();
            if (check) {
                AppUser user = userService.getAndCheckByPhone(userid);
                returnMap.put("status", 1);
                returnMap.put("userid", user.getPhone());
                //名字需要先Base64加密在urlencode加密
                String nickName = StringUtils.isNotBlank(user.getRealName())?user.getRealName():user.getNickName();
//                //Base64加密
//                String encodeStr = Base64.getEncoder().encodeToString(nickName.getBytes());
//                //urlencode加密
//                nickName = URLEncoder.encode(encodeStr,"UTF-8");
                returnMap.put("nickname",nickName);
                AppFile file = fileService.getFileByKey(StringUtils.isNoneBlank(user.getHeadIcon()) ? user.getHeadIcon() : BaseVo.DEFAULT_AVATAR_IMAGE);
                returnMap.put("avatar", file.getSrc());
            } else {
                log.error("保利威外部授权验签失败");
                returnMap.put("status", 0);
            }
            log.info("bolyv 返回参数:{}",JSON.toJSONString(returnMap));
            response.setContentType("application/json;charset=UTF-8");
            PrintWriter out = response.getWriter();
            out.write(JSON.toJSONString(returnMap));
            out.flush();
            out.close();
        } catch (Exception e) {
            log.error("保利威外部授权回调失败:{} \r\n 堆栈信息:{}",e.getMessage(), BusinessException.collectExceptionStackMsg(e));
        }
    }


    private boolean check(String userId, String channelId, String ts, String token) {
        try {
            PlChannelAuthGetRequest request = new PlChannelAuthGetRequest(appId, secret);
            //设置参数
            request.setChannelId(Integer.valueOf(channelId));
            //获得结果
            List<PLChannelAuthResult> auth = myPLChannelService.getAuth(request);
            for (PLChannelAuthResult result : auth) {
                if (!"N".equals(result.getEnabled()) && result.getRank() == 1) {
                    if ("external".equals(result.getAuthType())) {
                        String sign = MD5Util.toMD5(result.getExternalKey() + userId + result.getExternalKey() + ts);
                        return sign.equals(token);
                    }
                }
            }
        } catch (Exception e) {
            log.error("保利威验签调用失败:{} \r\n 堆栈信息:{}",e.getMessage(), BusinessException.collectExceptionStackMsg(e));
        }
        log.info("保利威回调验签失败，不做处理");
        return false;
    }

    private boolean check(String timestamp,String sign) {
        try {
            return sign.equals(MD5Util.toMD5(secret+timestamp));
        } catch (Exception e) {
            log.error("保利威直播状态验签调用失败:{} \r\n 堆栈信息:{}",e.getMessage(), BusinessException.collectExceptionStackMsg(e));
        }
        log.info("保利威直播状态回调验签失败，不做处理");
        return false;
    }

    //预处理authSetting
    private ChannelAuthSettingBody pretreatmentAuthSetting(ChannelAuthSettingBody authSettingBody) {
        switch (authSettingBody.getAuthType()) {
            case "pay":
            case "code":
            case "phone":
            case "info":
            case "custom":
            case "direct":
                throw new BusinessException(CodeMsg.POLYV_ERR, "不支持当前类型");
            case "external":
                authSettingBody.setExternalKey(UUID.randomUUID().toString().substring(0, 8));
                authSettingBody.setExternalUri(externalUri);
                break;
            default:
                authSettingBody.setAuthType("none");
                authSettingBody.setRank((byte) 1);
                authSettingBody.setEnabled("N");
        }
        return authSettingBody;
    }

    //预处理authSetting
    private ChannelBasicSettingBody pretreatmentBasicSetting(ChannelBasicSettingBody basicSettingBody) {
        if (StringUtils.isNotBlank(basicSettingBody.getCoverImg())) {
            AppFile file = fileService.getFileByKey(basicSettingBody.getCoverImg());
            if (file != null) {
                basicSettingBody.setCoverImg(file.getSrc());
            }
        }
        return basicSettingBody;
    }


    public void streamNotify(HttpServletRequest request, HttpServletResponse response){
        String timestamp = request.getParameter("timestamp");
        String sign = request.getParameter("sign");
        boolean check = check(timestamp, sign);
        try {
            if (check) {
                String status = request.getParameter("status");
                Integer channelId = Integer.valueOf(request.getParameter("channelId"));
                String sessionId = request.getParameter("sessionId");
                Long start = Long.valueOf(request.getParameter("startTime"));
                if("live".equalsIgnoreCase(status)){
                    LiveRoom room = liveRoomService.getNoLiveRoom(channelId);
                    room.setSessionId(StringUtils.isNotBlank(room.getSessionId())?room.getSessionId()+","+sessionId:sessionId);
                    if(room.getStart()==null)room.setStart(start);
                    liveRoomService.save(room);
                }else if("end".equalsIgnoreCase(status)){
                    LiveRoom room = liveRoomService.getEndLiveRoom(channelId,sessionId);
                    Long endTime = Long.valueOf(request.getParameter("endTime"));
                    room.setEnd(endTime);
                    liveRoomService.save(room);
                }
            }else{
                log.info("保利威直播状态回调验签失败，不做处理");
            }
        } catch (Exception e) {
            log.error("保利威直播状态回调处理失败:{} \r\n 堆栈信息:{}",e.getMessage(), BusinessException.collectExceptionStackMsg(e));
        }
    }
}
